package com.yueke.gemini.modules.seckill;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RPermitExpirableSemaphore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.yueke.gemini.modules.springSession.TestController;
import com.google.common.util.concurrent.RateLimiter;



/**
 *  秒杀接口
 * @author qxw
 * @data 2018年8月30日下午4:47:31
 */
@RestController
@RequestMapping(value = "/seckill")
public class SeckillController {
	private static final Logger log = LoggerFactory.getLogger(TestController.class);
	
	 //使用Guava的RateLimiter进行限流控制（单机）  每秒100请求数
	 //https://segmentfault.com/a/1190000012875897  源码解析
	  RateLimiter rateLimiter = RateLimiter.create(100);  
	 
       /**
		* 执行秒杀方法
		* @param request
		* @return
	    */
	  @RequestMapping("/placeAnOrder")
	  public Map<String, Object> placeAnOrder (HttpServletRequest request){
	      Map<String, Object> map = new HashMap<>();
	      RLock fairLock=null;
		  String permitId="";
		  RPermitExpirableSemaphore semaphore=null;
	      try {
	    	  //基于Redis的Redisson的分布式可过期性信号量  限流操作
	    	  semaphore = RedissonUtils.getRedisson().getPermitExpirableSemaphore("rateLimiter_key");
	    	  //设置信号量
	    	  semaphore.trySetPermits(500);
	    	  
	    	  //获取一个信号，有效期只有60秒钟。 未获取到会阻塞
	    	  permitId = semaphore.acquire(60, TimeUnit.SECONDS);
	    	 
	    	 // 尝试加锁，最多等待10秒，上锁以后10秒自动解锁
		     fairLock = RedissonUtils.getRedisson().getLock("lock_key");
		  	 boolean res = fairLock.tryLock(10, 10, TimeUnit.SECONDS);
			  	if(res){
		  			if(updateService()==0){
			    		  map.put("code", 0);
			    		  map.put("msg", "秒杀成功");  		 
			    	  }else{
			    		  map.put("code",-1);
			    		  map.put("msg", "库存不足");		
			    	 }	    		
		  		}else{
		  			map.put("code",-2);
		    		map.put("msg", "活动太火爆了,正在排队中....");
		    		//释放
		    		semaphore.release(permitId);
		  		}
		} catch (Exception e) {
			 log.error("秒杀接口异常",e);
		}finally{
			//释放锁
			if(fairLock!=null){ fairLock.unlock();}
			if(StringUtils.isNotEmpty(permitId)){semaphore.release(permitId);}
		}
	       return map;
	  }
	  
	    /**    
			* 执行秒杀方法  单机限流操作
			* @param request
			* @return
		    */
		  @RequestMapping("/placeAnOrder2")
		  public Map<String, Object> placeAnOrder2 (HttpServletRequest request){
		      Map<String, Object> map = new HashMap<>();
		      try {
		        //该方法会阻塞线程，直到令牌桶中能取到令牌为止才继续向下执行，并返回等待的时间
//		    	double time=rateLimiter.acquire();
//		        log.info("等待时间" +time); 
		    	  
		    	  
		    	 //判断能否在3秒内得到令牌，如果不能则立即返回false，不会阻塞程序  
		        if (!rateLimiter.tryAcquire(3000, TimeUnit.MILLISECONDS)){  
		            log.info("短期无法获取令牌，真不幸，排队也瞎排");
		            map.put("code",-2);
		    		map.put("msg", "活动太火爆了,正在排队中....");
		    		return map;
		        }  
		        
		    
		    	// 尝试加锁，最多等待10秒，上锁以后10秒自动解锁
		    	RLock fairLock = RedissonUtils.getRedisson().getLock("lock_key");
		  		boolean res = fairLock.tryLock(10, 10, TimeUnit.SECONDS);
		  		if(res){
		  			if(updateService()==0){
			    		  map.put("code", 0);
			    		  map.put("msg", "秒杀成功");
			    		fairLock.unlock();
			    	  }else{
			    		  map.put("code",-1);
			    		  map.put("msg", "库存不足");
			    	 }
		  		}else{
		  			map.put("code",-2);
		    		map.put("msg", "活动太火爆了,正在排队中....");
		  		}
			} catch (Exception e) {
				log.error("秒杀接口异常",e);
				map.put("code",500);
			}
		       return map;
		  }
	  
		   /**
		    * 模拟业务处理操作
		    */
		  public static int updateService(){
			  try {
				log.info("线程："+Thread.currentThread().getName()+" 进行秒杀业务处理");
				Thread.sleep(1000);
			} catch (Exception e) {
				e.printStackTrace();
			}
			return 0;
		  }
}
